/* map.c */
/* author: jiqing */
/* create: 2011-12-22 */

#include "map.h"

void tile_wipe(Tile * tile)
{
	tile->block = 0;
	tile->tile_index = -1;
}

void tile_copy(Tile * this_tile, Tile that_tile)
{
	this_tile->block = that_tile.block;
	this_tile->tile_index = that_tile.tile_index;
}


Map *map_new(short size_x, short size_y)
{
    Map *map = (Map *)malloc(sizeof(Map));
    if(map){
        map->size_x = size_x;
        map->size_y = size_y;
        if(size_x * size_y > 0) {
            map->tiles = (Tile *)malloc
                (sizeof(Tile) * size_x * size_y);
            if(map->tiles){
                int i;
                for(i = 0; i < size_x * size_y; i++){
                    tile_wipe(&map->tiles[i]);
                }
            }
            else {
                printf("malloc for map failed!\n");
                return NULL;
            }
        }
    }
    return map;
}
	
void map_destroy(Map *map)
{
    if(map){
        if(map->tiles){
            free(map->tiles);
            map->tiles = NULL;
        }
        free(map);
        map = NULL;
    }
}

bool map_resize(Map *map, short size_x, short size_y)
{
	Tile * temp;
    short old_size_x = map->size_x;
    short old_size_y = map->size_y;
	short old_tile_num = old_size_x * old_size_y;
	int i;

	if(map->tiles) {		
		temp = (Tile *)malloc(sizeof(Tile) * old_tile_num);
        if(!temp)
            return false;
		for (i = 0; i< old_tile_num; i++){
			tile_copy(& temp[i], map->tiles[i]);
		}
	}
    map_destroy(map);
    map = map_new(size_x, size_y);
    if(!map)
        return false;
	
	if(size_x * size_y > 0)	{
		for(i = 0; i < old_tile_num; i++){
			int n = (i / old_size_x) * size_x + (i % old_size_x);
			if (n < size_x * size_y)
			{
				tile_copy(& map->tiles[n], temp[i]);
				
			}
			else break;
		}
	}

    free(temp);
    temp = NULL;
    return true;
}

void map_draw(Map *map, SDL_Surface *screen, SDL_Surface *surf_tile,
              bool show_grid, bool show_block)
{
    if(!map || !map->tiles)
        return;

    short tile_surf_cols = surf_tile->w / TILE_SIZE;

    SDL_Rect rect_src, rect_dest;
    rect_src.w = TILE_SIZE;
    rect_src.h = TILE_SIZE;
    rect_dest.w = TILE_SIZE;
    rect_dest.h = TILE_SIZE;

    int i;
    for(i = 0; i < map->size_x * map->size_y; i ++){
        rect_dest.x = (i % map->size_x) * TILE_SIZE;
        rect_dest.y = (i / map->size_x) * TILE_SIZE;

        if(map->tiles[i].tile_index >= 0) {
            rect_src.x = (map->tiles[i].tile_index % tile_surf_cols)
                * TILE_SIZE;
            rect_src.y = (map->tiles[i].tile_index / tile_surf_cols)
                * TILE_SIZE;
            SDL_BlitSurface(surf_tile, &rect_src, screen,
                            &rect_dest);
        }
        else {
            SDL_FillRect(screen, &rect_dest, 0x00000000);
        }

        // draw grid
        if(show_grid)
            rectangleColor(screen, rect_dest.x, rect_dest.y,
                           rect_dest.x + TILE_SIZE,
                           rect_dest.y + TILE_SIZE, GRID_COLOR);

        // draw block
        if(show_block && map->tiles[i].block){
            lineColor(screen, rect_dest.x, rect_dest.y,
                      rect_dest.x + TILE_SIZE, 
                      rect_dest.y + TILE_SIZE, BLOCK_FLAG_COLOR);
            lineColor(screen, rect_dest.x + TILE_SIZE, rect_dest.y,
                      rect_dest.x, rect_dest.y + TILE_SIZE,
                      BLOCK_FLAG_COLOR);
        }
    }
}

Map * map_load(const char *map_file)
{
    FILE *fp;
    fp = fopen(map_file, "rb");
    if(fp == NULL){
        printf("open map file %s failed!\n", map_file);
        return NULL;
    }

    short size_x, size_y;
    fread(&size_x, sizeof(short), 1, fp);
    fread(&size_y, sizeof(short), 1, fp);
    if(size_x <= 0 || size_y <= 0){
        fclose(fp);
        return NULL;
    }

    Map *map = map_new(size_x, size_y);
    if(map){
        int i;
        for( i = 0; i < map->size_x * map->size_y; i++)
            fread(&map->tiles[i], sizeof(Tile), 1, fp);
    }

    fclose(fp);
    return map;
}

void map_save(Map *map, const char *map_file)
{
    if(!map)
        return;

    FILE *fp;
    fp = fopen(map_file, "wb");
    if(fp == NULL){
        printf("open map file %s for saving failed!\n", map_file);
        return;
    }

    fwrite(&map->size_x, sizeof(short), 1, fp);
    fwrite(&map->size_y, sizeof(short), 1, fp);
    if(map->tiles){
        int i;
        for(i = 0; i < map->size_x * map->size_y; i++)
            fwrite(&map->tiles[i], sizeof(Tile), 1, fp);
    }
    fclose(fp);
}


void map_text_out(Map *map)
{
    if(!map || !map->tiles)
        return;

    printf("w: %d; h: %d\n", map->size_x, map->size_y);

    int i;
    int old_y = 0;
    for(i = 0; i < map->size_x * map->size_y; i ++){
        if(old_y != i / map->size_x){
            printf("\n");
            old_y = i / map->size_x;
        }

        printf("%d ", map->tiles[i].tile_index);
    }
    printf("\n");
}

